package com.fowo.api.datainterface.aspect;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.webservice.SoapClient;
import cn.hutool.http.webservice.SoapProtocol;
import cn.hutool.http.webservice.SoapUtil;
import cn.hutool.log.level.Level;
import com.alibaba.fastjson.JSONObject;
import com.fowo.api.datainterface.constants.Constants;
import com.fowo.api.datainterface.entity.DatainterfaceLog;
import com.fowo.api.datainterface.service.DatainterfaceLogService;
import com.fowo.api.datainterface.util.Common;
import com.fowo.api.datainterface.util.JsonUtil;
import com.fowo.api.datainterface.util.RestUtilK3Cloud;
import com.fowo.api.datainterface.util.k3cloud.domain.Authentication;
import com.fowo.api.sys.annotation.RedisSyncLock;
import com.fowo.api.sys.component.ExecuteScriptEngine;
import com.kingdee.bos.webapi.entity.IdentifyInfo;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 代理基类
 */
@Component
@NoArgsConstructor
@Slf4j
public class BaseAspect {

    private volatile String businessType;

    public BaseAspect(String businessType) {
        this.businessType = businessType;
    }

    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(); //设置重试策略
        retryPolicy.setMaxAttempts(3);
        retryTemplate.setRetryPolicy(retryPolicy);

        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); //设置退避策略 间隔:10s
        fixedBackOffPolicy.setBackOffPeriod(10000L);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

        return retryTemplate;
    }


    /**
     * 发送请求(用于记录日志等行为)
     *
     * @param auth
     * @param formId
     * @param method
     * @param params
     * @param descriptions
     * @return
     */
    @RedisSyncLock
    public Object k3cloudrequest(IdentifyInfo auth, String formId, String method, String params, String readWriteMode, String descriptions) {
        DatainterfaceLog builderLog = SpringUtil.getBean(DatainterfaceLogService.class).builderLog(businessType, formId, method, params, auth, JsonUtil.getObjectToString(descriptions));
        return round(() -> SpringUtil.getBean(RestUtilK3Cloud.class).k3cloudrequest(auth, formId, method, params), builderLog, readWriteMode);

    }


    /**
     * 发送请求(用于记录日志等行为)
     *
     * @param auth
     * @param formId
     * @param method
     * @param params
     * @param descriptions
     * @return
     */
    @RedisSyncLock
    public Object k3cloudrequest(String url, Authentication auth, String formId, String method, Object params, String readWriteMode, String descriptions) {
        DatainterfaceLog builderLog = SpringUtil.getBean(DatainterfaceLogService.class).builderLog(businessType, formId, method, params, auth, JsonUtil.getObjectToString(descriptions));
        return round(() -> SpringUtil.getBean(RestUtilK3Cloud.class).k3cloudrequest(url, auth, formId, method, params), builderLog, readWriteMode);

    }

    /**
     * 发送请求(用于记录日志等行为)
     *
     * @param url     请求地址
     * @param method  请求方式
     * @param headers 请求头  可空
     * @param params  请求body参数 可空
     * @return ResponseEntity<responseType>
     */
    @RedisSyncLock
    public <T> Object httpRequest(String url, HttpMethod method, Object params, HttpHeaders headers, Class<T> clazz, String readWriteMode, String descriptions) {
        DatainterfaceLog builderLog = SpringUtil.getBean(DatainterfaceLogService.class).builderLog(businessType, url, method.name(), params, headers, descriptions);
        return round(() -> SpringUtil.getBean(ExecuteScriptEngine.class).httpRequest(url, method, params, headers, clazz), builderLog, readWriteMode);
    }

    /**
     * 发送请求(用于记录日志等行为)
     *
     * @param url    请求地址
     * @param method 请求方式
     * @param params 请求body参数 可空
     * @return ResponseEntity<responseType>
     */
    @RedisSyncLock
    public <T> Object soapRequest(JSONObject auth, String url, String method, Map<String, Object> params, String readWriteMode, String descriptions) {
        DatainterfaceLog builderLog = SpringUtil.getBean(DatainterfaceLogService.class).builderLog(businessType, url, method, params, Convert.toStr(MapUtil.getStr(auth, Constants.EBOEXP_SOAPACTION) + method), descriptions);
        return round(() -> {
                    SoapClient client = SoapUtil.createClient(url, SoapProtocol.SOAP_1_2)
                            .header(Constants.EBOEXP_SOAPACTION, MapUtil.getStr(auth, Constants.EBOEXP_SOAPACTION) + method)
                            .setMethod(MapUtil.getStr(auth, Constants.EBOEXP_PREFIX) + method, MapUtil.getStr(auth, Constants.EBOEXP_NAMESPACEURI));
                    //下面方法List类型无法处理
                    //client.setParams(params, true);
                    for (Map.Entry<String, Object> item : MapUtil.wrap(params)) {
                        SpringUtil.getBean(Common.class).setParam(client.getMethodEle(), item.getKey(), item.getValue(), client.getMethodEle().getPrefix());
                    }
                    return client.send(false);
                }
                , builderLog, readWriteMode);
    }

    /**
     * 包装发送请求(用于记录日志等行为)
     *
     * @param target
     * @param builderLog
     * @return
     */
    public Object round(Func0 target, DatainterfaceLog builderLog, String readWriteMode) {
        TimeInterval interval = new TimeInterval();
        String writeLog = Convert.toStr(SpringUtil.getProperty("interface.write-log.enabled"), "all");
        final Object[] res = {null};
        try {
            interval.start();
            try {
                SpringUtil.getBean(RetryTemplate.class).execute((RetryCallback<Object, IllegalAccessException>) context -> {
                    System.out.println("准备发起调用..." + DateUtil.now());
                    res[0] = target.callWithRuntimeException();
                    return res[0];
                });
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
            builderLog.setInvokWasteTime(interval.intervalMs());
        } catch (Exception ex) {
            builderLog.setExceptionContent(StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            builderLog.setResponseStatus(Convert.toStr(HttpStatus.HTTP_INTERNAL_ERROR));
            builderLog.setLogType(Level.ERROR.name());
            if (StrUtil.equalsIgnoreCase(writeLog, Constants.INTERFACE_WRITELOG_ENABLED_ERROR)) {
                SpringUtil.getBean(DatainterfaceLogService.class).writeLog(builderLog);
            }
        } finally {
            if (StrUtil.equalsIgnoreCase(writeLog, Constants.INTERFACE_WRITELOG_ENABLED_ALL)) {
                builderLog.setResponseContent(JsonUtil.getObjectToString(res));
                SpringUtil.getBean(DatainterfaceLogService.class).writeLog(builderLog);
            }
            return res[0];
        }








    }
}
